package com.nzw.service.impl.common;

import com.nzw.dao.common.IBaseDao;
import com.nzw.service.common.BaseService;
import com.nzw.utils.ReflectUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.persistence.Table;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by 许湛司 on 2017/4/21.
 */
@Service
public class BaseServiceImpl extends AbstractBaseService implements BaseService {
    @Autowired
    public IBaseDao baseDao;

    @Transactional
    @Override
    public <T> T addEntity(Map<String, Object> params, Class<T> clazz) {
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("table", clazz.getAnnotation(Table.class).name());
        resMap.put("column", params);
        if (baseDao.insert(resMap) > 0) {
            T obj = getBean(params, clazz);
            return obj;
        }
        return null;
    }

    @Transactional
    @Override
    public boolean addEntity(Object o) {
        Map<String, Object> resMap = reflectInsert(o);
        return baseDao.insert(resMap) > 0;
    }

    @Transactional
    @Override
    public <T> boolean bactchInsert(List<T> obj) {
        try {
            return baseDao.batchInsert(reflectBatchInsert(obj)) > 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Transactional
    @Override
    public <T> boolean bactchDelete(List<T> obj) {
        return baseDao.batchDelete(reflectBatchDelete(obj)) > 0;
    }

    @Transactional
    @Override
    public Long addEntityReturnId(Object o) {
        Map<String, Object> resMap = reflectInsert(o);
        System.out.println("res"+resMap);
        System.out.println(baseDao);
        if (baseDao.insert(resMap) > 0){
            System.out.println(resMap);
            return Long.valueOf((Integer)resMap.get("id"));//返回主键ID
        }

        return Long.valueOf(0);
    }

    @Transactional
    @Override
    public boolean modifyEntityById(Map<String, Object> params, Class<?> clazz, Integer id) {
        Map<String, Object> resMap = new HashMap<>();
        Map<String, Object> condition = new HashMap<>();
        condition.put("id", id);
        resMap.put("table", clazz.getAnnotation(Table.class).name());
        resMap.put("column", params);
        resMap.put("condition", condition);
        try {
            int success = baseDao.update(resMap);
            return success > 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Transactional
    @Override
    public boolean deleteEntityById(Long id, Class<?> clazz) {
        Map<String, Object> resMap = new HashMap<>();
        Map<String, Object> condition = new HashMap<>();
        condition.put("id", id);
        resMap.put("table", clazz.getAnnotation(Table.class).name());
        resMap.put("condition", condition);
        return baseDao.delete(resMap) > 0;
    }

    @Override
    public <T> T getEntityById(Long id, Class<T> clazz) {
        Map<String, Object> resultParam = baseDao.selectByMap(queryEntityByProperty(clazz, "id", id));
        T obj = getBean(resultParam, clazz);
        return obj;
    }

    @Transactional
    @Override
    public boolean saveOrUpdateEntity(Map<String, Object> params, Class<?> clazz) {
        Map<String, Object> resMap = new HashMap<>();
        if (params.containsKey("id")) {
            Map<String, Object> condition = new HashMap<>();
            condition.put("id", params.get("id"));
            resMap.put("table", clazz.getAnnotation(Table.class).name());
            params.remove("id");
            resMap.put("column", params);
            resMap.put("condition", condition);
            try {
                return baseDao.update(resMap) > 0;
            } catch (Exception e) {
                e.printStackTrace();
                return false;
            }
        }
        resMap.put("table", clazz.getAnnotation(Table.class).name());
        resMap.put("column", params);
        return baseDao.insert(resMap) > 0;
    }

    @Transactional
    @Override
    public boolean saveOrUpdateEntity(Object obj) {
        Map<String, Object> param = saveOrUpdate(obj);
        try {
            return param.containsKey("condition") ? baseDao.update(param) > 0 : baseDao.insert(param) > 0;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Transactional
    @Override
    public boolean updateEntityValues(Object obj) {
        Map<String, Object> param = queryColumnsEscapeNull(obj);
        try {
            return baseDao.update(param) > 0;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    @Transactional
    @Override
    public boolean updateEntity(Class<?> clazz, Map<String, Object> columns, Map<String, Object> condition) {
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("table", clazz.getAnnotation(Table.class).name());
        resMap.put("column", columns);
        resMap.put("condition", condition);
        try {
            return baseDao.update(resMap) >= 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    @Override
    public <T> List<T> loadAllEntity(Class<T> clazz) {
        Map<String, Object> param = reflectLoadAll(clazz);
        List<Map<String, Object>> datas = baseDao.select(param);
        return ReflectUtils.batchCopyBeans(datas, clazz);
    }

    @Transactional
    @Override
    public boolean deleteEntity(Object o) {
        Map<String, Object> param = reflectDelete(o);
        return baseDao.delete(param) > 0;
    }

    @Transactional
    @Override
    public <T> boolean deleteByMap(Class<T> clazz, Map<String, Object> condition) {
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("table", clazz.getAnnotation(Table.class).name());
        resMap.put("column", condition);
        return baseDao.delete(resMap) >= 0;
    }

    @Transactional
    @Override
    public <T> boolean deleteByOneProperty(Class<T> clazz, String column, Object val) {
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("table", clazz.getAnnotation(Table.class).name());
        Map<String, Object> condition = new HashMap<>();
        condition.put(column, val);
        resMap.put("condition", condition);
        return baseDao.delete(resMap) >= 0;
    }

    @Override
    public <T> T getEntityByOneProperty(Class<T> clazz, String propertyName, Object val) {
        Map<String, Object> params = queryEntityByProperty(clazz, propertyName, val);
        return getBean(baseDao.selectByMap(params), clazz);
    }

    @Override
    public <T> List<T> getEntitiesByPropertyName(Class<T> clazz, String propertyName, Object val) {
        Map<String, Object> params = queryEntityByProperty(clazz, propertyName, val);
        return ReflectUtils.batchCopyBeans(baseDao.select(params), clazz);
    }

    @Override
    public int getEntityCount(Class<?> clazz) {
        Map<String, Object> param = new HashMap<>();
        param.put("table", clazz.getAnnotation(Table.class).name());
        return baseDao.getCount(param);
    }

    @Override
    public int getEntityCountByPropertyName(Class<?> clazz, String propertyName, Object val) {
        Map<String, Object> param = new HashMap<>();
        param.put("table", clazz.getAnnotation(Table.class).name());
        Map<String, Object> condition = new HashMap<>();
        condition.put(propertyName, val);
        param.put("condition", condition);
        return baseDao.getCount(param);
    }

    @Override
    public int getCountByMap(Class<?> clazz, Map<String, Object> condition) {
        Map<String, Object> param = new HashMap<>();
        param.put("table", clazz.getAnnotation(Table.class).name());
        if (!CollectionUtils.isEmpty(condition))
            param.put("condition", condition);
        return baseDao.getCount(param);
    }

    @Override
    public <T> List<T> getEntityByMap(Class<T> clazz, Map<String, Object> condition) {
        Map<String, Object> map = queryEntityEnclosureParamsWholeColumn(clazz, condition);
        return ReflectUtils.batchCopyBeans(baseDao.select(map), clazz);
    }

    @Override
    public <T> T getUniqueEntityByMap(Class<T> clazz, Map<String, Object> condition) {
        List<T> list = getEntityByMap(clazz, condition);
        return list == null ? null : list.get(0);
    }

    @Override
    public <T> List<T> getEntityByMapEnclosureParams(Class<T> clazz, List<String> params, Map<String, Object> condition) {
        Map<String, Object> map = queryEntityEnclosureParamsAssignColumn(clazz, params, condition);
        return ReflectUtils.batchCopyBeans(baseDao.select(map), clazz);
    }

    @Override
    public <T> List<T> findEntityByPage(Class<T> clazz, Map<String, Object> condition, int start, int max, Object descParam) {
        Map<String, Object> param = condition != null ? queryEntityEnclosureParamsWholeColumn(clazz, condition) : reflectLoadAll(clazz);
        param.put("startPage", ((start - 1) * max));
        param.put("max", max);
        if (descParam != null)
            param.put("desc", descParam);
        List<Map<String, Object>> entity = baseDao.findEntitiesByPage(param);
        if (entity == null || entity.isEmpty())
            return null;
        List<T> entities = new ArrayList<>();
        for (Map<String, Object> map : entity) {
            entities.add(getBean(map, clazz));
        }
        return entities;
    }

    @Override
    public <T> List<T> getEntitiesBySort(Class<T> clazz,  Map<String, Object> condition, String sortParam, boolean isDesc) {
        Map<String, Object> param = condition != null ? queryEntityEnclosureParamsWholeColumn(clazz, condition) : reflectLoadAll(clazz);
        if (sortParam != null) {
            param.put("sortParam", sortParam);
            param.put("sortWay", isDesc ? "desc" : "asc");
        }
        return ReflectUtils.batchCopyBeans(baseDao.select(param), clazz);
    }

    @Override
    public Integer getSum(Class<?> clazz, Map<String, Object> condition, Object param) {
        if (param == null)
            return 0;
        Map<String, Object> params = new HashMap<>();
        params.put("table", clazz.getAnnotation(Table.class).name());
        params.put("column", param);
        if (!CollectionUtils.isEmpty(condition))
            params.put("condition", condition);
        return baseDao.getSum(params);
    }


}
